#include "Reason.h"
#include "Human.h"
#include "Choice.h"
#include "Decision.h"
#include "Utilities.h"

using namespace Hunger;

namespace Hunger
{
	Reason::Reason(Human * human)
	{
		reasoner = human;
	}

	Reason::~Reason()
	{
		delete reasoner;
		reasoner = 0;
	}

	Decision Reason::Choose(Choice * choice)
	{
		Decision decision;

		float responseAverage = 0;
		float emphasisAverage = 0;

		int importance = choice->importance;

		if(importance >= Importance::Vital)
		{
			decision.response += this->DecideOnValues(choice).response;
			decision.emphasis += this->DecideOnValues(choice).emphasis;

			decision.response += this->DecideOnAffinity(choice).response;
			decision.emphasis += this->DecideOnAffinity(choice).emphasis;

			responseAverage = (float)decision.response / 2.0f;
			decision.response = Utilities::Round(responseAverage);

			emphasisAverage = (float)decision.emphasis / 2.0f;
			decision.emphasis = Utilities::Round(emphasisAverage);
		}
		else if(importance > Importance::Inconsequential && importance < Importance::Vital)
		{
			decision.response += this->DecideOnAffinity(choice).response;
			decision.emphasis += this->DecideOnAffinity(choice).emphasis;

			decision.response += this->DecideOnMood().response;
			decision.emphasis += this->DecideOnMood().emphasis;

			decision.response += this->DecideOnValues(choice).response;
			decision.emphasis += this->DecideOnValues(choice).emphasis;

			decision.response += this->DecideOnWhim().response;
			decision.emphasis += this->DecideOnWhim().emphasis;

			responseAverage = (float)decision.response / 4.0f;
			decision.response = Utilities::Round(responseAverage);

			emphasisAverage = (float)decision.emphasis / 4.0f;
			decision.emphasis = Utilities::Round(emphasisAverage);
		}
		else if(importance <= Importance::Inconsequential)
		{
			decision.response += this->DecideOnAffinity(choice).response;
			decision.emphasis += this->DecideOnAffinity(choice).emphasis;

			decision.response += this->DecideOnWhim().response;
			decision.emphasis += this->DecideOnWhim().emphasis;

			decision.response += this->DecideOnMood().response;
			decision.emphasis += this->DecideOnMood().emphasis;

			responseAverage = (float)decision.response / 3.0f;
			decision.response = Utilities::Round(responseAverage);

			emphasisAverage = (float)decision.emphasis / 3.0f;
			decision.emphasis = Utilities::Round(emphasisAverage);
		}

		return decision;
	}

	std::vector<Decision> Reason::Choose(std::vector<Choice *> choices)
	{
		std::vector<Decision> decisions;

		for(int choice = 0; choice < choices.size(); choice++)
		{
			Decision decision = this->Choose(choices.at(choice));
			decisions.push_back(decision);
		}

		return decisions;
	}

	Decision Reason::DecideOnAffinity(Choice * choice)
	{
		Decision decision;

		Human * humanObject = choice->humanObject;
		Human * humanSubject = choice->humanSubject;

		int objectAffinity = 0;
		int subjectAffinity = 0;
		if(humanObject)
		{
			objectAffinity = reasoner->GetAffinity(humanObject);
		}
		if(humanSubject)
		{
			subjectAffinity = reasoner->GetAffinity(humanSubject);
		}

		if(objectAffinity > subjectAffinity)
		{
			if(objectAffinity > 50)
			{
				if(choice->harmsObject)
				{
					//return Response::No;
					return decision;
				}
				else
				{
					//return Response::Yes;
					return decision;
				}
			}
			else
			{
				if(choice->harmsObject)
				{
					//return Response::Yes;
					return decision;
				}
				else
				{
					//return Response::No;
					return decision;
				}
			}
		}
		else if(subjectAffinity > objectAffinity)
		{
			if(subjectAffinity > 50)
			{
				if(choice->harmsSubject)
				{
					//return Response::No;
					return decision;
				}
				else
				{
					//return Response::Yes;
					return decision;
				}
			}
			else
			{
				if(choice->harmsSubject)
				{
					//return Response::Yes;
					return decision;
				}
				else
				{
					//return Response::No;
					return decision;
				}
			}
		}
		else if(objectAffinity == subjectAffinity)
		{
			if(objectAffinity > 50)
			{
				if(choice->harmsObject)
				{
					//return Response::No;
					return decision;
				}
				else
				{
					//return Response::Yes;
					return decision;
				}
			}
			else
			{
				if(choice->harmsObject)
				{
					//return Response::Yes;
					return decision;
				}
				else
				{
					//return Response::No;
					return decision;
				}
			}
		}
	}

	Decision Reason::DecideOnWhim()
	{
		Decision decision;

		decision.response = Utilities::Random(Response::No, Response::Yes);
		decision.emphasis = Utilities::Random(0, 100);

		return decision;
	}

	Decision Reason::DecideOnMood()
	{
		Decision decision;

		int morale = reasoner->GetMorale();
		int empathy = reasoner->GetEmpathy();

		float moodAverage = (float)(morale + empathy) / 2.0f;
		if(moodAverage > 50)
		{
			//return Response::Yes;
			return decision;
		}
		else
		{
			//return Response::No;
			return decision;
		}
	}

	Decision Reason::DecideOnValues(Choice * choice)
	{
		//compare potential outcomes to personal values

		Decision decision;

		Values reasonerValues = reasoner->GetPersonalValues();

		int choiceSpiritual = choice->spiritualEffect;
		int spiritualDifference;
		if(choiceSpiritual > reasonerValues.spiritual)
		{
			spiritualDifference = choiceSpiritual - reasonerValues.spiritual;
		}
		else if(reasonerValues.spiritual > choiceSpiritual)
		{
			spiritualDifference = reasonerValues.spiritual - choiceSpiritual;
		}
		else if(reasonerValues.spiritual == choiceSpiritual)
		{
			spiritualDifference = 0;
		}

		int choiceSocial = choice->socialEffect;
		int socialDifference;
		if(choiceSocial > reasonerValues.social)
		{
			socialDifference = choiceSocial - reasonerValues.social;
		}
		else if(reasonerValues.social > choiceSocial)
		{
			socialDifference = reasonerValues.social- choiceSocial;
		}
		else if(reasonerValues.social == choiceSocial)
		{
			socialDifference = 0;
		}

		int choiceFamily = choice->familyEffect;
		int familyDifference;
		if(choiceFamily > reasonerValues.family)
		{
			familyDifference = choiceFamily - reasonerValues.family;
		}
		else if(reasonerValues.family > choiceFamily)
		{
			familyDifference = reasonerValues.family - choiceFamily;
		}
		else if(reasonerValues.family == choiceFamily)
		{
			familyDifference = 0;
		}

		int totalDifference = spiritualDifference + socialDifference + familyDifference;
		float averageDifference = (float)totalDifference / 3.0f;

		int difference = Utilities::Round(averageDifference);

		if(difference > 50)
		{
			//return Response::No;
			return decision;
		}
		else
		{
			//return Response::Yes;
			return decision;
		}
	}
}